// 
//  Copyright 2011  comphilip
// 
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
// 
//        http://www.apache.org/licenses/LICENSE-2.0
// 
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;

namespace Dict4Engkoo {
	/// <summary>
	/// Dict Context for processor
	/// </summary>
	public class DictContext : INotifyPropertyChanged {
		private IPAddress _clientIP;
		private string _rawCmd, _cmd;
		private string[] _cmdPars;
		private TextWriter _outWriter;
		private bool _optionMime;

		/// <summary>
		///  Initializes a new instance of the <see cref="T:DictContext"/> class
		/// </summary>
		/// <param name="ClientIP">Client IP</param>
		/// <param name="RawCommand">Client Raw Command</param>
		/// <param name="OutputWriter">Output Writer</param>
		public DictContext(IPAddress ClientIP, string RawCommand, TextWriter OutputWriter) {
			Utility.ArgumentValidator.ValidateNullArgument(ClientIP, "ClientIP");
			Utility.ArgumentValidator.ValidateNullArgument(RawCommand, "RawCommand");
			Utility.ArgumentValidator.ValidateNullArgument(OutputWriter, "OutputWriter");
			
			_clientIP = ClientIP;
			_rawCmd = RawCommand;
			_outWriter = OutputWriter;
			
			int seperatorIndex = RawCommand.IndexOfAny(new char[]{' ','\t'});
			_cmd = seperatorIndex != -1 ? RawCommand.Substring(0,seperatorIndex) : RawCommand;
			_cmdPars = ParseArgument(seperatorIndex != -1 ? RawCommand.Substring(seperatorIndex + 1) : string.Empty).ToArray();
		}

		/// <summary>
		/// Gets client IP address
		/// </summary>
		public IPAddress ClientIP {
			get { return _clientIP; }
		}

		/// <summary>
		/// Gets raw client command
		/// </summary>
		public string RawCommand {
			get { return _rawCmd; }
		}

		/// <summary>
		/// Gets client command 
		/// </summary>
		public string Command {
			get { return _cmd; }
		}

		/// <summary>
		/// Gets command parameters
		/// </summary>
		public string[] CommandParameters {
			get { return _cmdPars; }
		}

		/// <summary>
		/// Gets output text writer
		/// </summary>
		public TextWriter OutputWriter {
			get { return _outWriter; }
		}

		/// <summary>
		/// Gets or sets whether option mime is on
		/// </summary>
		public bool OptionMime {
			get { return _optionMime; }
			set { 
				if (value != _optionMime){
					_optionMime = value; 
					OnPropertyChanged(new PropertyChangedEventArgs("OptionMime"));
				}
			}
		}

		public event PropertyChangedEventHandler PropertyChanged;
		
		protected virtual void OnPropertyChanged(PropertyChangedEventArgs E){
			PropertyChangedEventHandler handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
			if (handler != null)
				handler(this, E);
		}
		
		private static IEnumerable<string> ParseArgument(string RawArgumentString){
			char? hasQuote = null;
			bool hasSlash = false;
			StringBuilder buffer = new StringBuilder();
			foreach(char item in RawArgumentString){
				if (hasSlash){
					buffer.Append(item);
					hasSlash = false;
					continue;
				}
				if (item.Equals('\\'))
					hasSlash = true;
				else if (item.Equals('\'') || item.Equals('"')){
					if (hasQuote.HasValue){
						if (hasQuote.Value.Equals(item))
							hasQuote = null;
						else
							buffer.Append(item);
					}else
						hasQuote = item;
				}else if (item.Equals(' ') || item.Equals('\t')){
					if (hasQuote.HasValue)
						buffer.Append(item);
					else if (buffer.Length > 0){
						yield return buffer.ToString();
						buffer.Length = 0;
					}
				}else
					buffer.Append(item);
			}
			
			if (buffer.Length > 0)
				yield return buffer.ToString();
		}
	}
}

